﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace DTS
{
    class Wykres : System.Windows.Forms.Panel
    {
        private Graphics g;
        private Graphics g_prawo;
        private Graphics g_daty;
        private Graphics g_wolumen;
        private Pen niebieskiePioro;
        private Pen czerwonePioro;
        private Pen szarePioro;
        private SolidBrush niebieskiPedzel;
        private SolidBrush bialyPedzel;
        private System.Windows.Forms.PictureBox pB;
        private System.Windows.Forms.PictureBox pB_prawo;
        private System.Windows.Forms.PictureBox pB_daty;
        private System.Windows.Forms.PictureBox pB_wolumen;
        private int pb_witdh;
        private int pb_height;
        private List<Swieczka> sw;

        public Wykres(System.Windows.Forms.PictureBox pBox1, System.Windows.Forms.PictureBox pBox2, System.Windows.Forms.PictureBox pBox3, System.Windows.Forms.PictureBox pBox4)
        {
            pB = pBox1;
            pB_prawo = pBox2;
            pB_daty = pBox3;
            pB_wolumen = pBox4;
            pB.Image = new Bitmap(700, 300);
            pB_prawo.Image = new Bitmap(55, 300);
            pB_daty.Image = new Bitmap(800, 30);
            pB_wolumen.Image = new Bitmap(700, 50);
            g = Graphics.FromImage(pB.Image);
            g_prawo = Graphics.FromImage(pB_prawo.Image);
            g_daty = Graphics.FromImage(pB_daty.Image);
            g_wolumen = Graphics.FromImage(pB_wolumen.Image);
            szarePioro = new Pen(Color.Gray);
            czerwonePioro = new Pen(Color.Red);
            niebieskiPedzel = new SolidBrush(Color.Blue);
            bialyPedzel = new SolidBrush(Color.White);
            niebieskiePioro = new Pen(Color.Blue);
            pb_witdh = pB.Width;
            pb_height = pB.Height;
            List<Swieczka> sw = new List<Swieczka>();
            sw.Clear();
        }

        public void rysujSkalePoziomo(double max, double min)
        {
            g.FillRectangle(bialyPedzel, new Rectangle(0, 0, pb_witdh, pb_height));
            int szer = (pb_height - 20) / 9;
            double roznica_cena = (max - min) / 9;
            if (max-min > 0.1)
            {
                for (int i = 0; i < 10; i++)
                {
                    g.DrawLine(szarePioro, new Point(0, 10 + i * szer), new Point(pb_witdh, 10 + i * szer)); 
                }
            }
            else
            {
                roznica_cena = (Math.Round(max, 2) - Math.Round(min, 2));
                roznica_cena /= 0.01; 
                szer = (int) ((double)(pb_height - 20) / roznica_cena);
                for (int i = 0; i <= roznica_cena; i++)
                {
                    g.DrawLine(szarePioro, new Point(0, 10 + i * szer), new Point(pb_witdh, 10 + i * szer));
                }
            }
            pB.Refresh();
        }

        public void rysujSkalePionowo(int liczbaDni, double max, double min)
        {
            double szer = (double)(pb_witdh - 40) / (double)(liczbaDni );
            double szer_duza = (double)(pb_witdh - 40) / 4;

            for (int i = 0; i <= 4; i++)
            {
                g.DrawLine(szarePioro, new Point((int)(20 + i * szer_duza), 0), new Point((int)(20 + i * szer_duza), pb_height));
            }          
            pB.Refresh();
        }

        public void rysujCeny(double max, double min)
        {
            g_prawo.FillRectangle(bialyPedzel, new Rectangle(0, 0, 55, 300));
            int szer = (pb_height - 20) / 9;
            double roznica_cena = (max - min) / 9;
            if (max - min > 0.1)
            {
                for (int i = 0; i < 10; i++)
                {
                    g_prawo.DrawString(Pomocnik.makeZeros(Math.Round((max - i * roznica_cena), 2).ToString()), new Font("Arial", 12), niebieskiPedzel, 2, i * szer);
                }
            }
            else
            {
                roznica_cena = (Math.Round(max, 2) - Math.Round(min, 2));
                roznica_cena /= 0.01;
                szer = (int)((double)(pb_height - 20) / roznica_cena);
                for (int i = 0; i <= roznica_cena; i++)
                {
                    g_prawo.DrawString(Pomocnik.makeZeros(Math.Round((max - i * 0.01), 2).ToString()), new Font("Arial", 12), niebieskiPedzel, 2, i * szer);
                }
            }
            pB_prawo.Refresh();
        }

        public void rysujDaty(int liczbaDni, DateTime data_od, DateTime data_do)
        {
            liczbaDni = (data_do - data_od).Days;
            g_daty.FillRectangle(bialyPedzel, new Rectangle(0, 0, 800, 30));
            int szer = (pb_witdh - 40) / 4;
            double roznica_dni = (double)liczbaDni / 4.0;
            //if (max - min > 0.1)
            {
                for (int i = 0; i <= 4; i++)
                {
                    g_daty.DrawString(data_od.AddDays((int)(i*roznica_dni)).ToShortDateString(), new Font("Arial", 12), niebieskiPedzel,  i * szer + 5 , 2);
                }
            }         
            pB_daty.Refresh();
        }

        public void rysujSwieczke(Swieczka s, int x, double max, double min, int szerokoscSwieczki)
        {
            double roznica_max = (max - s.GetMax()) / (max - min) * (pb_height - 20) + 10;
            double roznica_min = (max - s.GetMin()) / (max - min) * (pb_height - 20) + 10;
            double roznica_close = (max - s.GetClose()) / (max - min) * (pb_height - 20) + 10;
            double roznica_open = (max - s.GetOpen()) / (max - min) * (pb_height - 20) + 10;

            g.DrawLine(niebieskiePioro, new Point(x, (int)roznica_max), new Point(x, (int)roznica_min));
            if (s.GetClose() > s.GetOpen())
            {
                g.FillRectangle(bialyPedzel, new Rectangle(x - szerokoscSwieczki, (int)roznica_close, szerokoscSwieczki * 2, (int)(roznica_open - roznica_close)));
                g.DrawRectangle(niebieskiePioro, new Rectangle(x - szerokoscSwieczki, (int)roznica_close, szerokoscSwieczki * 2, (int)(roznica_open - roznica_close)));
            }
            else if (s.GetClose() < s.GetOpen())
                g.FillRectangle(niebieskiPedzel, new Rectangle(x - szerokoscSwieczki, (int)roznica_open, szerokoscSwieczki * 2, (int)(roznica_close - roznica_open)));
            else
            {
                g.DrawLine(niebieskiePioro, new Point(x - szerokoscSwieczki, (int)roznica_close), new Point(x + szerokoscSwieczki, (int)(roznica_close)));
            }
            pB.Refresh();
        }

        public void obliczenia(HistoriaSpolki daneWykres)
        {
            sw = new List<Swieczka>();
            sw.Clear();
            Swieczka s = new Swieczka();
            List<Swieczka> daneWykres2 = new List<Swieczka>(daneWykres.getDane());
            s = daneWykres2.ElementAt(0);
            int liczbaSwieczek = daneWykres2.Count;

            if (liczbaSwieczek <= 60)
            {
                foreach (var tmp in daneWykres2)
                {
                    sw.Add(tmp);
                }
            }
            else
            {
                int i = 0;
                int l1 = liczbaSwieczek / 60; // po ile normalnie na jedną swieczke
                int l2 = liczbaSwieczek - l1 * 60; //ile jeszcze swieczek zostalo
                int l3;

                foreach (var tmp in daneWykres2)
                {
                    if (i < l2) l3 = l1 + 1;
                    else l3 = l1;
                    Swieczka s2 = new Swieczka();
                    s2 = tmp;
                    if (i != 0 && i % l3 == 0) s = tmp;

                    if ((i) % l3 == 0) s.SetOpen(s2.GetOpen());

                    if ((i) % l3 == (l3 - 1)) s.SetClose(s2.GetClose());

                    if ((i) % (l3) != 0) s.SetVolume(s.GetVolume() + s2.GetVolume());

                    s.SetMax(Math.Max(s.GetMax(), s2.GetMax()));
                    s.SetMin(Math.Min(s.GetMin(), s2.GetMin()));

                    if ((i) % l3 == (l3 - 1))
                    {
                        sw.Add(s);
                        s = daneWykres2.ElementAt(i);
                    }
                    i++;
                }
            }
        }

        public void rysujWykresSwieczka(HistoriaSpolki daneWykres, DateTime data_od, DateTime data_do )
        {
            int liczbaDni = daneWykres.getDane().Count;
            double min = int.MaxValue;
            double max = int.MinValue;
            foreach (var tmp in daneWykres.getDane())
            {
                if (tmp.GetMin() < min) min = tmp.GetMin();
                if (tmp.GetMax() > max) max = tmp.GetMax();
            }

            rysujSkalePoziomo(max, min);
            rysujSkalePionowo(liczbaDni, max, min);
            rysujCeny(max, min);
            rysujDaty(liczbaDni, data_od, data_do);

            obliczenia(daneWykres);

            int liczbaSwieczek = sw.Count;
        
            int szerokoscSwieczki;
            double odstep_swieczek;
            if (liczbaSwieczek <= 30)       szerokoscSwieczki = (pb_witdh - 40 - 20 * (liczbaSwieczek -1));
            else              szerokoscSwieczki = (pb_witdh - 40 - 3 * (liczbaSwieczek - 1));

            odstep_swieczek = (double)(pb_witdh - 40) / (double)(liczbaSwieczek-1);
            szerokoscSwieczki = (int ) ((double) szerokoscSwieczki/(double)(2*(liczbaSwieczek)));
           
            int k = 0;
            foreach (Swieczka tmp in sw)
            {
                rysujSwieczke(tmp, (int) ((double)k * odstep_swieczek)+20, max, min, szerokoscSwieczki);
                k++;
            }

            rysujWolumen();
            
        }

        public void rysujWykresLinia(HistoriaSpolki daneWykres, DateTime data_od, DateTime data_do)
        {
            int liczbaDni = daneWykres.getDane().Count;
            double min = int.MaxValue;
            double max = int.MinValue;
            foreach (var tmp in daneWykres.getDane())
            {
                if (tmp.GetClose() < min) min = tmp.GetClose();
                if (tmp.GetClose() > max) max = tmp.GetClose();
            }

            rysujSkalePoziomo(max, min);
            rysujSkalePionowo(liczbaDni, max, min);
            rysujCeny(max, min);
            rysujDaty(liczbaDni, data_od, data_do);

            obliczenia(daneWykres);

            List<Swieczka> daneWykres2 = new List<Swieczka>(daneWykres.getDane());
            //daneWykres2.Reverse();         

            int liczbaPunktow = daneWykres2.Count;
            double odstep = (double)(pb_witdh - 40) / (double)(liczbaPunktow - 1);
          
            Swieczka s = new Swieczka();
            s = daneWykres2.ElementAt(0);
            daneWykres2.RemoveAt(0);

            int k = 0;
            foreach (Swieczka tmp in daneWykres2)
            {
                double roznica_od = (max - s.GetClose()) / (max - min) * (pb_height - 20) + 10;
                double roznica_do = (max - tmp.GetClose()) / (max - min) * (pb_height - 20) + 10;
                g.DrawLine(niebieskiePioro, new Point((int)((double)k * odstep+20), (int)roznica_od), new Point((int)((double)(k+1) * odstep+20), (int)roznica_do));
                s = daneWykres2.ElementAt(k );               
                k++;
            }
            pB.Refresh();
            rysujWolumen();
        }

        public void rysujWolumen()
        {

            int liczbaSwieczek = sw.Count;
            double odstep = (double)(pb_witdh - 40) / (double)(liczbaSwieczek - 1);
            int k = 0;

            double min = int.MaxValue;
            double max = int.MinValue;
            foreach (var tmp in sw)
            {
                if (tmp.GetVolume() < min) min = tmp.GetVolume();
                if (tmp.GetVolume() > max) max = tmp.GetVolume();
            }
            min = 0;
            g_wolumen.FillRectangle(bialyPedzel, new Rectangle(0, 0, 700, 50));
            foreach (Swieczka tmp in sw)
            {
                double roznica = (tmp.GetVolume()) / (max - min) * (50.0) + 10;
                g_wolumen.DrawLine(niebieskiePioro, new Point((int)((double)k * odstep + 20), 50), new Point((int)((double)k  * odstep + 20), 50-(int)roznica));
                k++;
            }
            pB_wolumen.Refresh(); 
        }
    }
}
